﻿//#include <windows.h>
//#include <gdiplus.h>
//#include <winsock2.h>
//#include <iostream>
//#include <vector>
//#include <thread>
//
//#pragma comment(lib, "gdiplus.lib")
//#pragma comment(lib, "ws2_32.lib")
//
//using namespace Gdiplus;
//using namespace std;
//
//// 🔹 获取 JPEG 编码器 CLSID
//int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
//    UINT num = 0, size = 0;
//    GetImageEncodersSize(&num, &size);
//    if (size == 0) return -1;
//
//    vector<BYTE> buffer(size);
//    ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)buffer.data();
//    GetImageEncoders(num, size, pImageCodecInfo);
//
//    for (UINT i = 0; i < num; ++i) {
//        if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) {
//            *pClsid = pImageCodecInfo[i].Clsid;
//            return i;
//        }
//    }
//    return -1;
//}
//
//// 🔹 捕获屏幕并保存为 JPEG 内存流
//bool CaptureScreenToJpeg(vector<BYTE>& outBuffer, ULONG quality = 50) {
//    int width = GetSystemMetrics(SM_CXSCREEN);
//    int height = GetSystemMetrics(SM_CYSCREEN);
//
//    HDC hScreenDC = GetDC(NULL);
//    HDC hMemDC = CreateCompatibleDC(hScreenDC);
//    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
//    SelectObject(hMemDC, hBitmap);
//
//    // 将屏幕内容复制到内存中
//    BitBlt(hMemDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY);
//
//    // 用 GDI+ 将 HBITMAP 转为 JPEG 内存流
//    IStream* pStream = nullptr;
//    CreateStreamOnHGlobal(NULL, TRUE, &pStream);
//
//    CLSID clsidJpeg;
//    if (GetEncoderClsid(L"image/jpeg", &clsidJpeg) < 0) {
//        cout << "❌ 找不到 JPEG 编码器" << endl;
//        DeleteObject(hBitmap);
//        DeleteDC(hMemDC);
//        ReleaseDC(NULL, hScreenDC);
//        return false;
//    }
//
//    Bitmap bmp(hBitmap, NULL);
//    EncoderParameters encoderParams;
//    encoderParams.Count = 1;
//    encoderParams.Parameter[0].Guid = EncoderQuality;
//    encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
//    encoderParams.Parameter[0].NumberOfValues = 1;
//    encoderParams.Parameter[0].Value = &quality;
//    bmp.Save(pStream, &clsidJpeg, &encoderParams);
//
//    // 提取字节流
//    HGLOBAL hGlobal = NULL;
//    GetHGlobalFromStream(pStream, &hGlobal);
//    SIZE_T size = GlobalSize(hGlobal);
//    BYTE* pData = (BYTE*)GlobalLock(hGlobal);
//    outBuffer.assign(pData, pData + size);
//
//    GlobalUnlock(hGlobal);
//    pStream->Release();
//
//    // 清理资源
//    DeleteObject(hBitmap);
//    DeleteDC(hMemDC);
//    ReleaseDC(NULL, hScreenDC);
//    return true;
//}
//
//// 🔹 客户端主类
//class RemoteClient {
//public:
//    string server_ip = "192.168.2.15";
//    int server_port = 8888;
//    SOCKET sock = INVALID_SOCKET;
//    bool running = true;
//
//    void start() {
//        initGDIPlus();
//        initSocket();
//
//        while (running) {
//            if (connectServer()) {
//                cout << "✅ 已连接服务器\n";
//                thread sender(&RemoteClient::sendScreen, this);
//                sender.detach();
//
//                receiveCommands();
//            }
//            cout << "⚠️ 断开连接，3 秒后重连...\n";
//            this_thread::sleep_for(chrono::seconds(3));
//        }
//
//        cleanup();
//    }
//
//private:
//    ULONG_PTR gdiToken = 0;
//
//    void initGDIPlus() {
//        GdiplusStartupInput gdiplusStartupInput;
//        GdiplusStartup(&gdiToken, &gdiplusStartupInput, NULL);
//    }
//
//    void initSocket() {
//        WSADATA wsaData;
//        WSAStartup(MAKEWORD(2, 2), &wsaData);
//    }
//
//    bool connectServer() {
//        sock = socket(AF_INET, SOCK_STREAM, 0);
//        if (sock == INVALID_SOCKET) return false;
//
//        sockaddr_in addr{};
//        addr.sin_family = AF_INET;
//        addr.sin_port = htons(server_port);
//        addr.sin_addr.s_addr = inet_addr(server_ip.c_str());
//
//        if (connect(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
//            closesocket(sock);
//            return false;
//        }
//        return true;
//    }
//
//    void sendScreen() {
//        while (running) {
//            vector<BYTE> jpegData;
//            if (!CaptureScreenToJpeg(jpegData, 50)) continue;
//
//            int len = static_cast<int>(jpegData.size());
//            int nlen = htonl(len);
//
//            if (send(sock, (char*)&nlen, 4, 0) <= 0) break;
//            if (send(sock, (char*)jpegData.data(), len, 0) <= 0) break;
//
//            this_thread::sleep_for(chrono::milliseconds(100));
//        }
//        closesocket(sock);
//    }
//
//    void receiveCommands() {
//        char buffer[1024];
//        while (running) {
//            int ret = recv(sock, buffer, sizeof(buffer) - 1, 0);
//            if (ret <= 0) break;
//
//            buffer[ret] = '\0';
//            string cmd(buffer);
//            processCommand(cmd);
//        }
//        closesocket(sock);
//    }
//
//    void processCommand(const string& cmd) {
//        if (cmd.rfind("move,", 0) == 0) {
//            int x, y;
//            sscanf(cmd.c_str(), "move,%d,%d", &x, &y);
//            SetCursorPos(x, y);
//        } else if (cmd.rfind("click,", 0) == 0) {
//            int x, y;
//            sscanf(cmd.c_str(), "click,%d,%d", &x, &y);
//            SetCursorPos(x, y);
//            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
//            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
//        }
//    }
//
//    void cleanup() {
//        if (sock != INVALID_SOCKET) closesocket(sock);
//        WSACleanup();
//        GdiplusShutdown(gdiToken);
//    }
//};
//
//// 🔹 主函数
//int main() {
//    RemoteClient client;
//    client.start();
//    return 0;
//}

// remote_client_fixed.cpp
#include <windows.h>
#include <gdiplus.h>
#include <winsock2.h>
#include <objidl.h>
#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
#include <mutex>
#include <chrono>
#include <string>

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "ws2_32.lib")

using namespace Gdiplus;
using namespace std;

// 固定发送给服务端的采集分辨率（避免裁切/比例问题）
const int CAPTURE_W = 1280;
const int CAPTURE_H = 720;

// 获取 JPEG 编码器 CLSID
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    UINT num = 0, size = 0;
    if (GetImageEncodersSize(&num, &size) != Ok || size == 0) return -1;

    vector<BYTE> buffer(size);
    ImageCodecInfo* pImageCodecInfo = reinterpret_cast<ImageCodecInfo*>(buffer.data());
    if (GetImageEncoders(num, size, pImageCodecInfo) != Ok) return -1;

    for (UINT i = 0; i < num; ++i) {
        if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[i].Clsid;
            return static_cast<int>(i);
        }
    }
    return -1;
}

// 捕获屏幕并保存为指定大小的 JPEG 内存流
bool CaptureScreenToJpeg(vector<BYTE>& outBuffer, ULONG quality = 50) {
    int screenW = GetSystemMetrics(SM_CXSCREEN);
    int screenH = GetSystemMetrics(SM_CYSCREEN);

    HDC hScreenDC = GetDC(NULL);
    if (!hScreenDC) return false;
    HDC hMemDC = CreateCompatibleDC(hScreenDC);
    if (!hMemDC) {
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenW, screenH);
    if (!hBitmap) {
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    HGDIOBJ hOld = SelectObject(hMemDC, hBitmap);
    if (!hOld) {
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    if (!BitBlt(hMemDC, 0, 0, screenW, screenH, hScreenDC, 0, 0, SRCCOPY)) {
        SelectObject(hMemDC, hOld);
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    // 将 HBITMAP 转为 GDI+ Bitmap
    Bitmap srcBmp(hBitmap, NULL);

    // 创建目标 Bitmap（固定分辨率）
    Bitmap dstBmp(CAPTURE_W, CAPTURE_H, PixelFormat32bppARGB);
    Graphics g(&dstBmp);
    // 等比例或拉伸（这里拉伸到目标大小，保持所有像素信息）
    g.SetInterpolationMode(InterpolationModeHighQualityBicubic);
    g.DrawImage(&srcBmp, 0, 0, CAPTURE_W, CAPTURE_H);

    // 保存为 JPEG 到 IStream
    IStream* pStream = nullptr;
    if (CreateStreamOnHGlobal(NULL, TRUE, &pStream) != S_OK) {
        SelectObject(hMemDC, hOld);
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    CLSID clsidJpeg;
    if (GetEncoderClsid(L"image/jpeg", &clsidJpeg) < 0) {
        pStream->Release();
        SelectObject(hMemDC, hOld);
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    EncoderParameters encoderParams;
    encoderParams.Count = 1;
    encoderParams.Parameter[0].Guid = EncoderQuality;
    encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
    encoderParams.Parameter[0].NumberOfValues = 1;
    encoderParams.Parameter[0].Value = &quality;

    Status s = dstBmp.Save(pStream, &clsidJpeg, &encoderParams);
    if (s != Ok) {
        pStream->Release();
        SelectObject(hMemDC, hOld);
        DeleteObject(hBitmap);
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hScreenDC);
        return false;
    }

    // 提取流数据
    STATSTG statstg;
    if (pStream->Stat(&statstg, STATFLAG_NONAME) == S_OK) {
        ULONGLONG size = statstg.cbSize.QuadPart;
        if (size > 0) {
            HGLOBAL hGlobal = NULL;
            if (GetHGlobalFromStream(pStream, &hGlobal) == S_OK) {
                BYTE* pData = (BYTE*)GlobalLock(hGlobal);
                if (pData) {
                    outBuffer.assign(pData, pData + static_cast<size_t>(size));
                    GlobalUnlock(hGlobal);
                }
            }
        }
    } else {
        // 回退方式
        HGLOBAL hGlobal = NULL;
        if (GetHGlobalFromStream(pStream, &hGlobal) == S_OK) {
            SIZE_T size = GlobalSize(hGlobal);
            BYTE* pData = (BYTE*)GlobalLock(hGlobal);
            if (pData && size > 0) {
                outBuffer.assign(pData, pData + size);
                GlobalUnlock(hGlobal);
            }
        }
    }

    pStream->Release();

    // 清理 GDI 资源
    SelectObject(hMemDC, hOld);
    DeleteObject(hBitmap);
    DeleteDC(hMemDC);
    ReleaseDC(NULL, hScreenDC);

    return !outBuffer.empty();
}

// 可靠发送所有字节
bool send_all(SOCKET sock, const char* data, int total) {
    int sent = 0;
    while (sent < total) {
        int ret = send(sock, data + sent, total - sent, 0);
        if (ret == SOCKET_ERROR) return false;
        if (ret == 0) return false;
        sent += ret;
    }
    return true;
}

// 客户端主类
class RemoteClient {
public:
    string server_ip = "192.168.2.15";
    int server_port = 8888;   // 图片通道端口
    int ctrl_port = 8889;     // 控制通道端口（默认 port+1）
    SOCKET sock = INVALID_SOCKET;      // 图片通道 socket
    atomic<bool> running;
    mutex sockMutex;

    RemoteClient(): running(false) {}

    void start() {
        initGDIPlus();
        initSocket();

        // 启动控制接收线程（负责接收服务端的 move/click 指令）
        thread ctrlThread(&RemoteClient::control_listener, this);
        ctrlThread.detach();

        while (true) {
            if (!connectServer()) {
                cout << "⚠️ 连接服务器失败（图像通道），3 秒后重试...\n";
                this_thread::sleep_for(chrono::seconds(3));
                continue;
            }

            cout << "✅ 图像通道已连接\n";
            running.store(true);

            // 发送屏幕线程
            thread senderThread(&RemoteClient::sendScreenLoop, this);
            // 接收命令（可选：我们把主要命令通道放在 ctrlThread）
            // 此处主线程仅等待 senderThread 完成（连接断开）
            if (senderThread.joinable()) senderThread.join();

            running.store(false);
            closesocket(sock);
            sock = INVALID_SOCKET;

            cout << "⚠️ 图像通道断开，3 秒后重连...\n";
            this_thread::sleep_for(chrono::seconds(3));
        }

        //cleanup(); // unreachable; add exit logic if needed
    }

    void initGDIPlus() {
        GdiplusStartupInput gdiplusStartupInput;
        gdiplusStartupInput.GdiplusVersion = 1;
        GdiplusStartup(&gdiToken, &gdiplusStartupInput, NULL);
    }

    void initSocket() {
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
    }

    bool connectServer() {
        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == INVALID_SOCKET) {
            cout << "socket 创建失败: " << WSAGetLastError() << endl;
            return false;
        }
        sockaddr_in addr{};
        addr.sin_family = AF_INET;
        addr.sin_port = htons((u_short)server_port);
        addr.sin_addr.s_addr = inet_addr(server_ip.c_str());

        if (connect(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
            cout << "connect 失败 (图像通道) 错误码: " << WSAGetLastError() << endl;
            closesocket(s);
            return false;
        }

        lock_guard<mutex> lk(sockMutex);
        sock = s;
        return true;
    }

    void sendScreenLoop() {
        while (running.load()) {
            vector<BYTE> jpegData;
            if (!CaptureScreenToJpeg(jpegData, 50)) {
                this_thread::sleep_for(chrono::milliseconds(100));
                continue;
            }

            int len = static_cast<int>(jpegData.size());
            int nlen = htonl(len);

            {
                lock_guard<mutex> lk(sockMutex);
                if (sock == INVALID_SOCKET) break;
                if (!send_all(sock, reinterpret_cast<char*>(&nlen), 4)) break;
                if (!send_all(sock, reinterpret_cast<char*>(jpegData.data()), len)) break;
            }

            // 控制帧率：100ms（可调）
            this_thread::sleep_for(chrono::milliseconds(100));
        }
    }

    // 控制通道：连接到服务器的 ctrl_port，并循环接收指令
    void control_listener() {
        while (true) {
            SOCKET ctrlSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
            if (ctrlSock == INVALID_SOCKET) {
                this_thread::sleep_for(chrono::seconds(3));
                continue;
            }

            sockaddr_in addr{};
            addr.sin_family = AF_INET;
            addr.sin_port = htons((u_short)ctrl_port);
            addr.sin_addr.s_addr = inet_addr(server_ip.c_str());

            if (connect(ctrlSock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
                closesocket(ctrlSock);
                this_thread::sleep_for(chrono::seconds(3));
                continue;
            }

            // 连接成功后，向服务端发送 INFO,<width>,<height>
            string info = "INFO," + to_string(CAPTURE_W) + "," + to_string(CAPTURE_H);
            send_all(ctrlSock, info.c_str(), (int)info.length());

            // 接收控制命令
            char buf[256];
            while (true) {
                int ret = recv(ctrlSock, buf, sizeof(buf) - 1, 0);
                if (ret <= 0) break;
                buf[ret] = '\0';
                string cmd(buf);
                // 服务器发送的可能包含多个命令或部分命令，这里假设每次一次完整命令（简单）
                processControlCommand(cmd);
            }

            closesocket(ctrlSock);
            // 连接中断则重连循环
            this_thread::sleep_for(chrono::seconds(1));
        }
    }

    // 处理来自服务端的控制命令（格式: move,ratioX,ratioY 或 click,ratioX,ratioY）
    void processControlCommand(const string& cmd) {
        if (cmd.rfind("move,", 0) == 0) {
            double rx = 0, ry = 0;
            if (sscanf(cmd.c_str(), "move,%lf,%lf", &rx, &ry) == 2) {
                int real_w = GetSystemMetrics(SM_CXSCREEN);
                int real_h = GetSystemMetrics(SM_CYSCREEN);
                int x = static_cast<int>(rx * real_w + 0.5);
                int y = static_cast<int>(ry * real_h + 0.5);
                SetCursorPos(x, y);
            }
        } else if (cmd.rfind("click,", 0) == 0) {
            double rx = 0, ry = 0;
            if (sscanf(cmd.c_str(), "click,%lf,%lf", &rx, &ry) == 2) {
                int real_w = GetSystemMetrics(SM_CXSCREEN);
                int real_h = GetSystemMetrics(SM_CYSCREEN);
                int x = static_cast<int>(rx * real_w + 0.5);
                int y = static_cast<int>(ry * real_h + 0.5);
                SetCursorPos(x, y);
                // 鼠标点击 (左键)
                mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            }
        } else if (cmd.rfind("INFO,", 0) == 0) {
            // 若服务端也发 INFO，可解析；目前客户端主动发送 INFO，服务端接收
        } else {
            // 其他命令（可扩展）
            cout << "收到未知控制命令: " << cmd << endl;
        }
    }

    void cleanup() {
        lock_guard<mutex> lk(sockMutex);
        if (sock != INVALID_SOCKET) {
            closesocket(sock);
            sock = INVALID_SOCKET;
        }
        WSACleanup();
        if (gdiToken) GdiplusShutdown(gdiToken);
    }

private:
    ULONG_PTR gdiToken = 0;
};

int main() {
    RemoteClient client;
    // 根据需要修改 server_ip 和 server_port
    // client.server_ip = "192.168.2.15";
    // client.server_port = 8888;
    client.start();
    return 0;
}
